package com.avcompris.collections;

import static com.avcompris.util.ExceptionUtils.nonNullArgument;

import java.util.Comparator;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;

/**
 * an implmentation of {@link IntgerMap} that binds to a
 * {@link TreeMap}.
 */
public final class IntegerTreeMap<T> extends TreeMap<T, Integer> implements
		IntegerMap<T> {

	public IntegerTreeMap() {

	}

	public IntegerTreeMap(final Comparator<? super T> comparator) {

		super(comparator);
	}

	public IntegerTreeMap(final Map<? extends T, ? extends Integer> map) {

		super(map);
	}

	public IntegerTreeMap(
			final SortedMap<? extends T, ? extends Integer> sortedMap) {

		super(sortedMap);
	}

	/**
	 * for serialization.
	 */
	private static final long serialVersionUID = -5967826329201374411L;

	/**
	 * return a given integer in the map, creating it
	 * if necessary.
	 * 
	 * @return the value, never <tt>null</tt>.
	 */
	@Override
	@SuppressWarnings("unchecked")
	public Integer get(final Object key) {
		
		nonNullArgument(key, "key");
		
		return getInt((T) key);
	}

	/**
	 * return a given integer in the map, creating it
	 * if necessary.
	 * 
	 * @return the value, never <tt>null</tt>.
	 */
	@Override
	public synchronized int getInt(final T key) {

		final Integer value = super.get(key);

		if (value != null) {

			return value;
		}

		put(key, new Integer(0));

		return 0;
	}

	/**
	 * increment a given integer in the map, creating it (and incremeting it)
	 * if necessary.
	 * 
	 * @return the incremented value.
	 */
	@Override
	public int inc(final T key) {

		return inc(key, 1);
	}

	/**
	 * decrement a given integer in the map, creating it (and decremeting it)
	 * if necessary.
	 * 
	 * @return the decremented value.
	 */
	@Override
	public int dec(final T key) {

		return dec(key, 1);
	}

	/**
	 * increment a given integer in the map, creating it (and incremeting it)
	 * if necessary.
	 * 
	 * @return the incremented value.
	 */
	@Override
	public synchronized int inc(final T key, final int increment) {

		final Integer value = super.get(key);

		if (value != null) {

			final int newValue = value + increment;

			put(key, newValue);

			return newValue;
		}

		put(key, new Integer(increment));

		return increment;

	}

	/**
	 * decrement a given integer in the map, creating it (and decremeting it)
	 * if necessary.
	 * 
	 * @return the decremented value.
	 */
	@Override
	public int dec(final T key, final int decrement) {

		return inc(key, -decrement);
	}
}
